package tilegame;

import graphics.Animation;
import java.awt.*;
import java.util.Iterator;

import graphics.Sprite;
import java.awt.geom.AffineTransform;
import javax.swing.ImageIcon;
import tilegame.sprites.Element;
import test.GameCore;
import tilegame.sprites.Player;
import tilegame.sprites.PowerUp;
import tilegame.sprites.PowerUp.WangGoal;
import tilegame.sprites.Shot;

/**
The TileMapRenderer class draws a TileMap on the screen.
It draws all tiles, sprites, and an optional background image
centered around the position of the player.

<p>If the width of background image is smaller the width of
the tile map, the background image will appear to move
slowly, creating a parallax background effect.

<p>Also, three static methods are provided to convert pixels
to tile positions, and vice-versa.

<p>This TileMapRender uses a tile size of 64.
 */
public class TileMapRenderer {

    private static final int TILE_SIZE = 64;
    // the size in bits of the tile
    // Math.pow(2, TILE_SIZE_BITS) == TILE_SIZE
    private static final int TILE_SIZE_BITS = 6;
    private Image background;
    private Image upperDashboard;
    private Image lowerDashboard;
    private Image playerLife;
    private Image lifeMeter;

    /**
    Converts a pixel position to a tile position.
     */
    public static int pixelsToTiles(float pixels) {
        return pixelsToTiles(Math.round(pixels));
    }

    /**
    Converts a pixel position to a tile position.
     */
    public static int pixelsToTiles(int pixels) {
        // use shifting to get correct values for negative pixels
        return pixels >> TILE_SIZE_BITS;

        // or, for tile sizes that aren't a power of two,
        // use the floor function:
        //return (int)Math.floor((float)pixels / TILE_SIZE);
    }

    /**
    Converts a tile position to a pixel position.
     */
    public static int tilesToPixels(int numTiles) {
        // no real reason to use shifting here.
        // it's slighty faster, but doesn't add up to much
        // on modern processors.
        return numTiles << TILE_SIZE_BITS;

        // use this if the tile size isn't a power of 2:
        //return numTiles * TILE_SIZE;
    }

    /**
    Sets the background to draw.
     */
    public void setBackground(Image background) {
        this.background = background;
    }

    public void setUpperDashboard(Image dashboard) {
        this.upperDashboard = new ImageIcon(dashboard).getImage();
    }

    public void setLowerDashboard(Image dashboard) {
        this.lowerDashboard = dashboard;
    }

    public void setPlayerLife(Image playerLife) {
        this.playerLife = new ImageIcon(playerLife).getImage();
    }

    public void setLifeMeter(Image lifeMeter) {
        this.lifeMeter = new ImageIcon(lifeMeter).getImage();
    }

    public void drawIntro(Animation introAnim) {
    }

    /**
    Draws the specified TileMap.
     */
    public void draw(Graphics2D g, TileMap map,
            int screenWidth, int screenHeight) {
        Sprite player = map.getPlayer();
        int mapWidth = tilesToPixels(map.getWidth());

        // get the scrolling position of the map
        // based on player's position
        int offsetX = screenWidth / 2
                - Math.round(player.getX()) - TILE_SIZE;
        offsetX = Math.min(offsetX, 0);
        offsetX = Math.max(offsetX, screenWidth - mapWidth);

        // get the y offset to draw all sprites and tiles
        int offsetY = screenHeight
                - tilesToPixels(map.getHeight());

        // draw black background, if needed
        if (background == null
                || screenHeight > background.getHeight(null)) {
            g.setColor(Color.black);
            g.fillRect(0, 0, screenWidth, screenHeight);
        }

        // draw parallax background image
        if (background != null) {
            int x = offsetX
                    * (screenWidth - background.getWidth(null))
                    / (screenWidth - mapWidth);
            int y = screenHeight - background.getHeight(null);

            g.drawImage(background, x, y, null);
        }

        // draw the visible tiles
        int firstTileX = pixelsToTiles(-offsetX);
        int lastTileX = firstTileX
                + pixelsToTiles(screenWidth) + 1;
        for (int y = 0; y < map.getHeight(); y++) {
            for (int x = firstTileX; x <= lastTileX; x++) {
                Image image = map.getTile(x, y);
                if (image != null) {
                    g.drawImage(image,
                            tilesToPixels(x) + offsetX,
                            tilesToPixels(y) + offsetY,
                            null);
                }
            }
        }

        // draw player
        g.drawImage(player.getImage(),
                Math.round(player.getX()) + offsetX,
                Math.round(player.getY()) + offsetY,
                null);

        // draw sprites
        Iterator i = map.getSprites();
        while (i.hasNext()) {
            Sprite sprite = (Sprite) i.next();
            int x = Math.round(sprite.getX()) + offsetX;
            int y = Math.round(sprite.getY()) + offsetY;
            g.drawImage(sprite.getImage(), x, y, null);

            String sp = "";

            if (sprite instanceof PowerUp.WangLife) {
                sp = "+1 Life";
            } else if (sprite instanceof PowerUp.WangRapidShot) {
                sp = "Rapid Shot";
            } else if (sprite instanceof PowerUp.WangStrength) {
                sp = "x2 Strength";
            }

            g.drawString(sp, x, y);

            // wake up the creature when it's on screen
            if (sprite instanceof Element
                    && x >= 0 && x < screenWidth) {
                ((Element) sprite).wakeUp();

                if (lifeMeter != null) {
                    if (((Element) sprite).isAlive()) {
                        int distance = x;
                        for (int s = ((Element) sprite).getLife(); s > 0; s--) {
                            g.drawImage(lifeMeter, distance, y - 5, null);
                            distance = distance + lifeMeter.getWidth(null);
                        }
                    }
                }
            }
        }

        if (upperDashboard != null) {
            g.drawImage(upperDashboard, (screenWidth / 2) - (upperDashboard.getWidth(null) / 2), 0, null);
        }

        if (lowerDashboard != null) {
            g.drawImage(lowerDashboard, (screenWidth / 2) - (lowerDashboard.getWidth(null) / 2),
                    (screenHeight / 2) - (lowerDashboard.getHeight(null) / 2), null);
        }

        if (playerLife != null) {
            int distance = screenWidth / 20;

            for (int s = ((Player) player).getLife(); s > 0; s--) {
                g.drawImage(playerLife, distance, 25, null);
                distance = distance + playerLife.getWidth(null);
            }
        }

        g.drawString(GameCore.WANGBALLS_COLLECTED + " ", (float) screenWidth / 3.7f, 50);
        g.drawString(TileMapRenderer.TILE_SIZE - TileMapRenderer.pixelsToTiles(player.getX()) + 1 + " m", (float) screenWidth / 1.7f, 50);
        g.drawString(GameCore.POINTS + " pts", (float) screenWidth / 1.233f, 50);
    }
}
